#include "myproxy.h"

//~ void find_content_encoding(char* header_raw, struct struct_request_identity *requestIdentity) {
	//~ char* header_line;
	//~ char* current_token;
	//~ char* peek_token;
	//~ char* header_line_saveptr, *token_saveptr;
	//~ char* header_raw_temp = calloc(1, MAX_HEADER_SIZE);
	
	//~ header_raw_temp = strcpy(header_raw_temp, header_raw);
	//~ header_line = strtok_r(header_raw_temp, "\r\n", &header_line_saveptr);
	//~ while(header_line != NULL) {
		//~ current_token = strtok_r(header_line, " ", &token_saveptr);
		//~ peek_token = strtok_r(NULL, " ", &token_saveptr);
		//~ while(1) {
			//~ //printf("current token = <%s>, next token = <%s>\n", current_token, peek_token);

			//~ if (strcmp(current_token, "Content-Encoding:") == 0&& peek_token != NULL) {
				//~ strcpy(requestIdentity->encoding, peek_token);
				//~ printf("Content-Encoding is: %s\n", requestIdentity->encoding);
				//~ break;
			//~ }

			//~ if (peek_token == NULL) {
				//~ break;
			//~ }
			//~ else {
				//~ current_token = peek_token;
				//~ peek_token = strtok_r(NULL, " ", &token_saveptr);
			//~ }
		//~ }
		//~ header_line = strtok_r(NULL, "\r\n", &header_line_saveptr);
	//~ }

//~ }

void find_content_encoding2(char* header_raw, struct struct_response_header* responseHeader) {
	char* header_line;
	char* current_token;
	char* peek_token;
	char* header_line_saveptr, *token_saveptr;
	char* header_raw_temp = calloc(1, MAX_HEADER_SIZE);
	
	memset(responseHeader->encoding, '\0', 20);

	header_raw_temp = strcpy(header_raw_temp, header_raw);
	header_line = strtok_r(header_raw_temp, "\r\n", &header_line_saveptr);
	while(header_line != NULL) {
		current_token = strtok_r(header_line, " ", &token_saveptr);
		peek_token = strtok_r(NULL, " ", &token_saveptr);
		while(1) {
			//printf("current token = <%s>, next token = <%s>\n", current_token, peek_token);

			if (strcmp(current_token, "Content-Encoding:") == 0 && peek_token != NULL) {
				
				printf("Content-Encoding is: %s\n", peek_token);
				strcpy(responseHeader->encoding, peek_token);
				
				free(header_raw_temp);
				return;
				//break;
			}

			if (peek_token == NULL) {
				break;
			}
			else {
				current_token = peek_token;
				peek_token = strtok_r(NULL, " ", &token_saveptr);
			}
		}
		header_line = strtok_r(NULL, "\r\n", &header_line_saveptr);
	}

}




char* parse_response_header(char* header_raw, struct struct_response_header *responseHeader) {
	char* header_line;
	char* current_token;
	char* peek_token;
	char* header_line_saveptr, *token_saveptr;

	responseHeader->is_keep_alive = FALSE;
	
	find_content_encoding2(header_raw, responseHeader);
	responseHeader->is_fix_length = 'X';		// represent no content message

	header_line = strtok_r(header_raw, "\r\n", &header_line_saveptr);
	while(header_line != NULL) {
		current_token = strtok_r(header_line, " ", &token_saveptr);
		peek_token = strtok_r(NULL, " ", &token_saveptr);
		while(1) {
			//printf("current token = <%s>, next token = <%s>\n", current_token, peek_token);
			if (((strcmp(current_token, "HTTP/1.1") == 0) || (strcmp(current_token, "HTTP/1.0") == 0)) && (peek_token != NULL)) {
//				sprintf(peek_token, "%d", responseHeader->status_code);
				responseHeader->status_code = atoi(peek_token);
			}
			// may be useless
			if (strcmp(current_token, "Connection:") == 0 && peek_token != NULL) {
				if(strcmp(peek_token, "close") == 0){
					//Close connection
					responseHeader->is_keep_alive = FALSE;
				}else{
					responseHeader->is_keep_alive = TRUE;
				}
			}
			
			if (strcmp(current_token, "Proxy-Connection:") == 0 && peek_token != NULL) {
				if (strcmp(peek_token, "keep-alive") == 0){
					responseHeader->is_keep_alive = TRUE;
				}else{
					responseHeader->is_keep_alive = FALSE;
				}
			}

			if (strcmp(current_token, "Content-Length:") == 0&& peek_token != NULL) {
				responseHeader->is_fix_length = TRUE;
				sscanf(peek_token, "%ud", &responseHeader->content_length);
			}
			
			if (strcmp(current_token, "Transfer-Encoding:") == 0) {
				responseHeader->is_fix_length = FALSE;
			}
			
			if (strcmp(current_token, "Last-Modified:") == 0) {
//				printf("Last-Modified: %s\n", strtok_r(NULL, "\0", &token_saveptr));
				// do sth to make the time string to time_t;
				strcpy(responseHeader->ims_time_string, strtok_r(NULL, "\0", &token_saveptr));
				
				//check cache-date and compare to imf???
				
			}

			if (peek_token == NULL) {
				break;
			}
			else {
				current_token = peek_token;
				peek_token = strtok_r(NULL, " ", &token_saveptr);
			}
		}
		header_line = strtok_r(NULL, "\r\n", &header_line_saveptr);
	}

	if (responseHeader->is_fix_length == 'X') {
		responseHeader->is_no_centent = TRUE;
	} else {
		responseHeader->is_no_centent = FALSE;
	}

	// Return the updated address for FREE
	return header_raw;
}


int process_response(char* response_header_raw, int response_header_size, struct struct_request_identity *requestIdentity) {
	struct struct_response_header responseHeader;
	char* response_header_raw_for_parsing = calloc(1, response_header_size + 1);
	char require_keep_alive = TRUE;
	int client_keep_alive = 1;

	

	response_header_raw_for_parsing = strncpy(response_header_raw_for_parsing, response_header_raw, response_header_size);
	parse_response_header(response_header_raw_for_parsing, &responseHeader);
	free(response_header_raw_for_parsing);
	
	if (requestIdentity->is_interested_type == TRUE) {
		switch (responseHeader.status_code){
			// Case 1: Cache/ overwrite the object and forward the HTTP response to client.
			case 200:
				printf("\033[1;32mProxy> Case 1 response: Cache/ overwrite the object and forward the HTTP response to client.\033[0m\n");
				case1_response_process(response_header_raw, &responseHeader, requestIdentity, TRUE);
				break;
			case 304: 
				// Case 2a: Retrieves the web object and returns it with HTTP 200 response.
				if ((requestIdentity->is_ims == TRUE) && (requestIdentity->is_cache_control == TRUE) && (requestIdentity->is_ims_modified == TRUE)) {
					printf("\033[1;32mProxy> Case 2a response: Retrieves the web object and returns it with HTTP 200 response.\033[0m\n");
//					find_content_encoding(response_header_raw, requestIdentity);
					case1_2b_request_process(requestIdentity);
				} else {
				// Case 2b: Construct and reply HTTP 304 response.
					printf("\033[1;32mProxy> Case 2b response: Construct and reply HTTP 304 response.\033[0m\n");
					case2a_request_process(requestIdentity);
					require_keep_alive = FALSE;
				}
				break;
			default :
				printf("\033[1;32mProxy> Case other (interested type): forward response, cache the data.\033[0m\n");
				require_keep_alive = case1_response_process(response_header_raw, &responseHeader, requestIdentity, TRUE);
				break;
		};
	} else {
		// Only forward the response if non-interested (no caching).
		printf("\033[1;32mProxy> Case other (not interested type): forward response.\033[0m\n");
		require_keep_alive = case1_response_process(response_header_raw, &responseHeader, requestIdentity, FALSE);
	}
	
	// If the response header has connection/ proxy: close, clock the connection between SERVER and PROXY
	if(responseHeader.is_keep_alive == FALSE){
		close(requestIdentity->server_socket_descriptor);
		printf("Proxy> Server's connection %d closed.\n", requestIdentity->server_socket_descriptor);
	}
	
	// If the response is HTTP 304 message/ message without content, client keep alive set to FALSE
	if (require_keep_alive == FALSE) {
		client_keep_alive = 0;
	}
	return client_keep_alive;
}

int receive_and_process_response_thread(struct struct_request_identity *requestIdentity) {
	char* response_header_raw = calloc(1, MAX_HEADER_SIZE);
	char buffer;
	int state = 0;
	int response_header_size = 0;
	int client_keep_alive, received_size = 0;

	printf("Proxy> Waiting for response on socket %d.\n", requestIdentity->server_socket_descriptor);
	printf("Proxy> Response is interested type? %c\n", requestIdentity->is_interested_type);

	/* Receive HTTP Header */
	do {
		//response_header_size += recvn(requestIdentity->server_socket_descriptor, &buffer, sizeof(char));

		if((received_size = recvn(requestIdentity->server_socket_descriptor, &buffer, sizeof(char))) == sizeof(char)){
			response_header_size = response_header_size + received_size;
		} else {
			//printf("Error char: <%d>, \\r is %d \\n is %d\n", (int) buffer, (int)'\r', (int)'\n');
			fprintf(stderr, "Error while reading a response from server socket %d.\n", requestIdentity->server_socket_descriptor);
			printf("Proxy> Receive and process response thread exits.\n");
			free(response_header_raw);
			return 0;
		}

		if(response_header_size >= MAX_HEADER_SIZE){
			fprintf(stderr, "\033[1;31mProxy> Error: Too big response header, this should not be possible.\033[0m\n");
			free(response_header_raw);
			return 0;	// disconnect the client
			//exit(-1);
		}
		response_header_raw = strncat(response_header_raw, &buffer, 1);

		// Receive HTTP Header until \r\n\r\n
		if ((buffer == '\r') && ((state == 0) || (state == 2)))
			state++;
		else
			if ((buffer == '\n') && ((state == 1) || (state == 3)))
				state++;
			else
				state = 0;
	} while(state != 4);
	//printf("\033[1;31mResponse from HTTP server\n\033[0m");
	//printf("\033[1;31m%s\n\033[0m", response_header_raw);
	
	client_keep_alive = process_response(response_header_raw, response_header_size, requestIdentity);

	free(response_header_raw);
	printf("Proxy> Receive and process response thread exits.\n");	
	return client_keep_alive;
}

